/*
 * @Author: spring
 * @version:
 * @Date: 2022-09-07 14:51:23
 * @LastEditors: spring
 * @LastEditTime: 2022-09-19 10:29:38
 * @Descripttion:
 */

#include "../include/Com_thread.h"

using namespace std;

extern void epoll_add(int fd, uint32_t events);

void *Com_thread(void *args)
{
    int rv = 0;
    const thread_args Comargs = *(thread_args *)args;
    std::vector<pair<wait_arg, wait_arg>> &wait_terminal = Comargs.arr_com;
    // int epoll_fd = Comargs.epoll_fd;

    // 给app发信号 提示小车上线。

    char buf[COM_TOP_SIZE] = {0};
    memcpy(buf, &Comargs.car.top.data_type, sizeof(int));
    buf[COM_TOP_SIZE - 1] = CAR_ACK;

    if (send(Comargs.app.fd, buf, COM_TOP_SIZE, 0) == -1)
    {
        perror("send to app car oneline fail\n");
    }

    pollfd fds[2];
    fds[0].fd = Comargs.app.fd;
    fds[0].events = POLLIN;
    fds[1].fd = Comargs.car.fd;
    fds[1].events = POLLIN;
    while (1)
    {
        rv = poll(fds, 2, -1); // 2s
        if (rv == -1)
        {
            perror("poll failed");
            pthread_exit(NULL);
        }
        else if (rv == 0)
        {
            printf("poll timeout\n");
            continue;
        }
        if (fds[0].revents == POLLIN)
        {
            // app 控制信息
            char *cmd;
            int len = readCom(fds[0].fd, &cmd);
            if (len == -1)
            {
                // 数据接收出错
                fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
                perror("recv failed");
                fprintf(stderr, "app 接收命令，可能会导致后面数据失序。");
                close(fds[0].fd);
                pthread_exit(NULL);
            }
            else if (len == 0)
            {
                // app 断开连接.将小车加入等待状态。并将小车的套接字交由epoll监听。
                // 对共享数据进行操作  互斥。
                pair<wait_arg, wait_arg> node;
                node.first.top.data_type = 0;
                node.second = Comargs.car;

                pthread_mutex_lock(&mutex_wait_terminal);
                wait_terminal.push_back(node);
                pthread_mutex_unlock(&mutex_wait_terminal);

                epoll_add(Comargs.car.fd, EPOLLIN);

                fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
                fprintf(stderr, "add %d,app close(%d)\n", Comargs.car.fd, Comargs.app.fd);

                pthread_exit(NULL);
            }

            // 将数据转发给小车
            send(fds[1].fd, cmd, len, 0);
            printf("send car:");
            for (int i = 0; i < len; i++)
            {
                printf("%02x", cmd[i]);
            }
            printf("\n");
            free(cmd);
        }
        if (fds[1].revents == POLLIN)
        {
            // 小车环境信息
            char *cmd;
            int len = readCom(fds[1].fd, &cmd);
            if (len == -1)
            {
                // 数据接收出错
                fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
                perror("recv failed");
                fprintf(stderr, "小车 接收命令 ，可能会导致后面数据失序。");
                close(fds[1].fd);
                pthread_exit(NULL);
            }
            else if (len == 0)
            {
                // 小车 断开连接 向 app发送断开信息，并将app添加到等待队列，套接字交由epoll管理
                char buf[COM_TOP_SIZE] = {0};
                memcpy(buf, &Comargs.car.top.data_type, sizeof(int));
                buf[12] = CAR_ACK_FAIL;
                send(fds[0].fd, buf, COM_TOP_SIZE, 0);

                // 添加监听
                pair<wait_arg, wait_arg> node;
                node.first = Comargs.app;
                node.second.top.data_type = 0;

                pthread_mutex_lock(&mutex_wait_terminal);
                wait_terminal.push_back(node);
                pthread_mutex_unlock(&mutex_wait_terminal);

                epoll_add(Comargs.app.fd, EPOLLIN);

                fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
                fprintf(stderr, "add %d,car close(%d)\n", Comargs.app.fd, Comargs.car.fd);

                pthread_exit(NULL);
            }
            struct head top_temp;
            unPackCmdHead(&top_temp, cmd);

            // 将数据转发给app
            printf("len is%d\n", len);
    
            int rv = write(fds[0].fd, cmd, len);
            if (-1 == rv)
            {
                fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
                perror("send to app failed");
                pthread_exit(NULL);
            }

            printf("send app:ok send size is%d\n", rv);

            if (top_temp.cmd_type == VIDEO)
            {
                // static int video_index = 0;
                // char buf_temp[32] = {0};
                // sprintf(buf_temp, "./img%d.jpg", video_index++);
        
                // printf("%s size is:%lld\n", buf_temp, top_temp.size);

                // int fd_img = open(buf_temp, O_CREAT | O_WRONLY, 0666);
                // if (fd_img == -1)
                // {
                //     perror("open failed");
                // }
                // else
                // {
                //     int send_size = 0;
                //     if ((send_size = write(fd_img,cmd+13, top_temp.size)) != 1)
                //     {
                //         perror("write failed");
                //     }
                //     printf("send %s size is:%d done img\n", buf_temp, send_size);
                //     close(fd_img);
                // }
                // puts(buf_temp);
            }
            else
            {
                for (int i = 0; i < len; i++)
                {
                    printf("%02x", cmd[i]);
                }
                printf("\n");
            }

            free(cmd);
        }
    }
}

/**
 * @msg: 接收一个完整的命令数据，通过cmd返回
 * @param {int} socketfd ：通信套接字
 * @param {char} *： 返回值。
 * @return {*}：成功返回 接收的大小，失败返回-1，套接字断开返回0；
 */
int readCom(int socketfd, char **cmd)
{
    char cmdtop[COM_TOP_SIZE] = {0};
    int rv = 0;
    rv = recv(socketfd, cmdtop, sizeof(cmdtop), MSG_WAITALL);
    if (rv == -1)
    {
        return -1;
    }
    else if (rv == 0)
    {
        // 当前接口断开连接
        fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
        return 0;
    }
    struct head top;
    unPackCmdHead(&top, cmdtop);
    *cmd = (char *)malloc((top.size + COM_TOP_SIZE) * sizeof(char));
    if (*cmd == NULL)
    {
        fprintf(stderr, "%s:%d ", __FILE__, __LINE__);
        perror("malloc failed");
        exit(-1);
    }

    // 获取头
    memcpy(*cmd, cmdtop, COM_TOP_SIZE);

    rv = recv(socketfd, *cmd + COM_TOP_SIZE, top.size, MSG_WAITALL);
    if (rv == -1)
    {
        perror("recv failed");
        printf("接收命令数据失败，可能会导致后面数据失序。");
        free(*cmd);
        return -1;
    }
    else if (rv == 0)
    {
        free(*cmd);
        return 0;
    }
    return COM_TOP_SIZE + top.size;
}
